*****************************************
                *                                       *
                *         RingZer0   Presents           *
                *                                       *
                *       Win32asm KEYGEN by PUSILLUS     *
                *                                       *
                *****************************************
				
				05/02/1999





L'AUTORE DI QUESTO TESTO NON SI PRENDE NESSUNA RESPONSABILITA' PER L'USO 
CHE NE VERRA' FATTO POICHE' E' STATO ESPRESSAMENTE CONCEPITO PER PURI 
SCOPI DITATTICI.                                        

tools necessari:

WDASM32 
SOFTICE
MASM

programma target:
Programmer's IDE for Win95/NT (software by design)

Questo programma e' facilmente crackabile forzando il jump in determinati 
punti, ma anche una protezione poco efficente puo' essere un valido esercizio
per le nostre menti bacate! Alla fine la filosofia del cracker non e' solo 
quella di riuscire, a tutti i costi, a violare un programma, ma soprattutto
quella di CAPIRE cosa fa una sequenza di codice per il PURO e SEMPLICE 
PIACERE di SAPERLO e per ACQUISIRE CONOSCENZE che NON A TUTTI APPARTENGONO 
(soprattutto a certi programmatori). 
Proprio per questi motivi, A PURO SCOPO DIDATTICO, proveremo a fare un keygen:


Lanciamo il programma ed entriamo nella maschera di registrazione: viene 
richiesto il nome dell'utente, il nome della societa' ed un codice di 
registrazione.

inseriamo dei valori a caso e prima di dare "ok" entriamo in SoftIce (ctrl-D)
e settiamo un bel : BPX GetDlgItemTextA.
Appena dato l'OK al programma ci si presentera' subito la finestra del SoftIce,
con F12 usciamo dalla API su cui abbiamo settato il break e torniamo nel nostro
progz. Noteremo che la api viene chiamata da "call ebp" .




:0040F939 57                      push edi
:0040F93A FFD5                    call ebp                       <---------- getdlgitemtexta
:0040F93C 6A32                    push 00000032


Andando avanti con F10 il debugger si blocchera' alle chiamate ad ebp:


:0040F93E 53                      push ebx
:0040F93F 6A66                    push 00000066
:0040F941 57                      push edi
:0040F942 FFD5                    call ebp                       <---------- getdlgitemtexta 
:0040F944 8D442410                lea eax, dword ptr [esp+10]
:0040F948 6800010000              push 00000100
:0040F94D 50                      push eax
:0040F94E 6A67                    push 00000067
:0040F950 57                      push edi
:0040F951 FFD5                    call ebp                       <---------- getdlgitemtexta
:0040F953 8D442410                lea eax, dword ptr [esp+10]
:0040F957 50                      push eax
:0040F958 E8F3930000              call 00418D50
:0040F95D 83C404                  add esp, 00000004
:0040F960 8BE8                    mov ebp, eax
:0040F962 56                      push esi


Usciti da questa sequenza troviamo la prima cosa interessante: dopo la call
a 00417260 viene confrontato il contenuto di EAX con un certo valore, il fatto che ci
siano dei riferimenti alle stringhe  "Gregory Braun" e "Software Design" mi ha incuriosito
molto quando ho disassemblato il programma e ho forzato il programma a non eseguire il
salto alla riga 0040f970. Come risultato ho ottenuto una  registrazione con quei 
dati! ...megalomania del programmatore?

Comunque il punto che ci interessa ancora non e' arrivato, io voglio registrare il programma
con un qualsiasi nome, non con il nome di chi lo ha fatto! Quindi eseguiamo il salto ed
andiamo avanti:


:0040F963 E8F8780000              call 00417260
:0040F968 83C404                  add esp, 00000004
:0040F96B 3D92A71901              cmp eax, 0119A792
:0040F970 7518                    jne 0040F98A                   ----------|
                                                                           |
* Possible StringData Ref from Data Obj ->"Gregory Braun"                  |
                                  |                                        |
:0040F972 684C734200              push 0042734C                            |
                                                                           |
* Reference To: KERNEL32.lstrcpyA, Ord:0296h                               |
                                  |                                        |
:0040F977 8B2DECB44300            mov ebp, dword ptr [0043B4EC]            |
:0040F97D 56                      push esi                                 |
:0040F97E FFD5                    call ebp                                 |
                                                                           |
* Possible StringData Ref from Data Obj ->"Software Design"                |
                                  |                                        |
:0040F980 683C734200              push 0042733C                            |
:0040F985 53                      push ebx                                 |
:0040F986 FFD5                    call ebp                                 |
:0040F988 EB07                    jmp 0040F991                             |
                                                                           |
* Referenced by a (U)nconditional or (C)onditional Jump at Address:        |
|:0040F970(C)                                                              |
|                                                                          |    
:0040F98A 3D3CCE5F0D              cmp eax, 0D5FCE3C         <--------------|
:0040F98F 750C                    jne 0040F99D


Incredibile, un'altra comparazione di eax con un valore strano! Ma stavolta non ho
indagato e sono andato avanti. Comunque si e' capito che il prog x verificare l'autenticita'
della chiave confronta EAX con qualcosaltro ;)

Siamo arrivati alla parte di codice che ci interessa: vengono fatte due call a 00416d90 e il
valore di EAX viene confrontato con EBP (indir. 0040f9a7) :

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040F988(U)
|
:0040F991 53                      push ebx
:0040F992 56                      push esi
:0040F993 E8F8730000              call 00416D90             <------ 
:0040F998 83C408                  add esp, 00000008
:0040F99B 8BE8                    mov ebp, eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040F98F(C)
|
:0040F99D 53                      push ebx
:0040F99E 56                      push esi
:0040F99F E8EC730000              call 00416D90             <------
:0040F9A4 83C408                  add esp, 00000008
:0040F9A7 3BC5                    cmp eax, ebp              <------ controllo codice
:0040F9A9 741E                    je 0040F9C9               <------ se giusto registra il prog
:0040F9AB 68CFEA0000              push 0000EACF                     altrimenti viene mostrata
                                                                    una message box di errore


Ecco la parte di codice che esegue il calcolo della chiave di registrazione:
all'indirizzo 00416d90 viene caricato in EAX l'indirizzo del "nome dell'utente"
all'indirizzo 00416d95 viene caricato in ESI l'indirizzo di una costante 
corrispondente al valore "CC0DEFED". Dopo la prima call a 00417260 vengono
esegute alcune operazioni sui registri, dopodiche' alla riga 00416dac viene
caricato in EAX l'offset che punta al "nome dell'organizzazione" e viene eseguita
nuovamente la call a 00417260. Tutti i valori puntati dai registri o presenti ad
un certo indirizzo, sono facilmente ispezionabili con il comado "d" (display) 
del softice. 




|:0040C722   , :0040F7D9   , :0040F993   , :0040F99F   
|
:00416D90 8B442404                mov eax, dword ptr [esp+04]    ; EAX <--- nome utente
:00416D94 56                      push esi
:00416D95 8B35705D4200            mov esi, dword ptr [00425D70]  ; ESI <--- CC0DEFED
:00416D9B 50                      push eax
:00416D9C 81CE78030000            or esi, 00000378
:00416DA2 E8B9040000              call 00417260			 <-------- 1^ call
:00416DA7 83C404                  add esp, 00000004
:00416DAA 03F0                    add esi, eax
:00416DAC 8B44240C                mov eax, dword ptr [esp+0C]    ; EAX <--- nome societa'
:00416DB0 50                      push eax
:00416DB1 E8AA040000              call 00417260			 <-------- 2^ call
:00416DB6 83C404                  add esp, 00000004
:00416DB9 03C6                    add eax, esi			 <- in EAX c'e' il codice ESATTO 
								    per sbloccare il programma
:00416DBB 5E                      pop esi
:00416DBC C3                      ret


Ora non rimane che vedere cosa succede quando viene eseguita la call a 00417260,
quindi disabilitiamo il bpx GetDlgItemTexta e settiamo un bpx 00416da2 e 
bpx 00416db1, ridiamo l'OK sulla maschera di registrazione. 
Ci troveremo in questa parte di codice che processera' prima il nome dell'utente
e poi, alla seconda call, il nome della societa':

:00417260 53                      push ebx
:00417261 56                      push esi
:00417262 8B74240C                mov esi, dword ptr [esp+0C]    <----- ESI  addr "nome utente"
:00417266 57                      push edi
:00417267 55                      push ebp
:00417268 33FF                    xor edi, edi
:0041726A 56                      push esi

* Reference To: KERNEL32.lstrlenA, Ord:029Ch
                                  |
:0041726B FF15F8B44300            Call dword ptr [0043B4F8]      <------ EAX lungh. "nome utente"
:00417271 85F6                    test esi, esi                  <- controlla che ESI non sia 0
:00417273 7432                    je 004172A7
:00417275 85C0                    test eax, eax			 <- contolla che EAX non sia 0
:00417277 742E                    je 004172A7
:00417279 B900000000              mov ecx, 00000000              <- inizializza ECX a 0 x usarlo come contatore
:0041727E 7E27                    jle 004172A7

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004172A5(C)
|
:00417280 0FBE9C08B89B4200        movsx ebx, byte ptr [eax+ecx+00429BB8] <- muove in EBX il contenuto di una particolare locazione di memoria *
:00417288 0FBE2C0E                movsx ebp, byte ptr [esi+ecx]		 <- usa ECX come puntatore x processare tutti i bytes del "nome Utente"
:0041728C 8D5101                  lea edx, dword ptr [ecx+01]
:0041728F 0FAFDD                  imul ebx, ebp
:00417292 0FBE89F09B4200          movsx ecx, byte ptr [ecx+00429BF0]     <- muove in ECX il contenuto di una particolare locazione di memoria *
:00417299 0FAFD9                  imul ebx, ecx
:0041729C 0FAFDA                  imul ebx, edx
:0041729F 03FB                    add edi, ebx
:004172A1 8BCA                    mov ecx, edx
:004172A3 3BC2                    cmp eax, edx				 
:004172A5 7FD9                    jg 00417280				<- esegue il ciclo fino a che non ha processato tutta la stringa

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00417273(C), :00417277(C), :0041727E(C)
|
:004172A7 8BC7                    mov eax, edi		
:004172A9 5D                      pop ebp
:004172AA 5F                      pop edi
:004172AB 5E                      pop esi
:004172AC 5B                      pop ebx
:004172AD C3                      ret

* Questa routine esegue dei calcoli sulle stringhe inserite sulla maschera di 
registrazione, ma usa anche dei valori particolari presenti agli indirizzi
00429BB8 e 00429BF0, non ci resta che adare a vedere cosa contengono queste 
locazioni:  


:00429BB8 23 73 65 72 42 26 6E 7A  #serB&nz  <-------
:00429BC0 7C 6D 66 4D 31 2F 35 28  |mfM1/5(
:00429BC8 21 73 64 24 4D 71 2E 7B  !sd$Mq.{
:00429BD0 73 5D 2B 73 46 6A 74 4B  s]+sFjtK
:00429BD8 70 7A 53 64 74 7A 6F 58  pzSdtzoX
:00429BE0 71 6D 62 5E 41 6C 40 64  qmb^Al@d
:00429BE8 76 3A 73 3F 78 2F 00 00  v:s?x/..
:00429BF0 7C 62 21 70 7A 2A 6C 73  |b!pz*ls  <-------
:00429BF8 3B 72 6E 7C 6C 66 24 76  ;rn|lf$v
:00429C00 69 5E 41 78 70 65 29 72  i^Axpe)r
:00429C08 78 35 61 69 63 26 39 2F  x5aic&9/
:00429C10 32 6D 35 6C 73 69 34 40  2m5lsi4@
:00429C18 30 64 6D 5A 77 39 34 63  0dmZw94c
:00429C20 6D 71 70 66 68 77 00 00  mqpfhw..
:00429C28 6D 41 50 49 20 66 75 6E  mAPI fun
:00429C30 63 74 69 6F 6E 20 4E 4F  ction NO
:00429C38 54 20 73 75 70 70 6F 72  T suppor


A questo punto siamo a conoscenza di tutti i dati che ci occorrono x fare la
nostra keygen. Ho scelto di farla in Win32asm perche' con un semplice
copia ed incolla, ed alcune piccole modifiche, della routine di calcolo del
codice di registrazione e' possibile raggiungere lo scopo, senza neanche
curarsi troppo di tutti calcoli che vengono eseguiti. Se avete gia letto il mio
tute su come fare una patch noterete che lo scheletro e' del tutto analogo
per entrambi i programmi, le cose cambiano quando viene premuto il tasto OK e la
dialogbox e' diversa perche' questa volta dobbiamo inserire dei valori:


---------------------------------------------
.386
.MODEL FLAT, STDCALL
include winicz.inc
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib

calcolo	PROTO: DWORD

.data
DlgName        db "MYDIALOG",0

dati1	db "#serB&nz|mfM1/5(!sd$Mq.{s]+sFjtKpzSdtzoXqmb^Al@dv:s?x/",0,0 ; dati estratti dalla locazione 00429BB8
dati2	db "|b!pz*ls;rn|lf$vi^Axpe)rx5aic&9/2m5lsi4@0dmZw94cmqpfhw",0,0 ; dati estratti dalla locazione 00429BF0

formato db "%lu",0
.data?
nome         db 40 dup(?),0
societa      db 40 dup(?),0
codice	     db 40 dup(0),0

hInstance  HINSTANCE ? 
hInstance1 HINSTANCE ?


.const
 IDC_EDIT2           equ       3003
 IDC_EDIT1           equ       3004
 IDC_EDIT3           equ       3005
 IDC_BUTTON2         equ       3007
 IDC_EXIT            equ       3000

.code

start:
     
     invoke GetModuleHandle, NULL
     mov    hInstance,eax
     invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
     invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
        mov   eax, OFFSET DlgProc
        invoke DialogBoxParam, hInst, ADDR DlgName,NULL,eax,NULL
        ret
WinMain endp
DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
     mov eax,hWnd
     mov hInstance1,eax
     mov   eax,uMsg
        .IF eax==WM_INITDIALOG
                invoke SetFocus,eax
        .ELSEIF eax==WM_CLOSE
                invoke EndDialog, hWnd,NULL
        .ELSEIF eax==WM_COMMAND
                mov eax,wParam
                        .IF ax==IDC_BUTTON2
                                shr eax,16
                                .IF ax == BN_CLICKED
                                 
 				  invoke GetDlgItemTextA,hInstance1,IDC_EDIT1,addr nome,40  
 				  invoke GetDlgItemTextA,hInstance1,IDC_EDIT2,addr societa,40  
                      	       
				  mov esi, 0cc0defedh		; valore estratto dalla loc. 00425D70
				  or esi, 00000378h
				  invoke calcolo, addr nome	; prima chiamata calcolo sul "nome utente"
				  add esi, eax
				  invoke calcolo, addr societa  ; seconda chiamata calcolo sul "nome societa"
				  add eax, esi
				  invoke wsprintfA,addr codice, addr formato,eax   ; il valore HEX viene convertito in decimale
				  invoke SetDlgItemText,hInstance1,IDC_EDIT3,addr codice   ; visualizzazione del codice
				  invoke UpdateWindow, hInstance1
                                .ENDIF
                        .ELSEIF ax == IDC_EXIT
                                shr eax,16
                                .IF ax==BN_CLICKED
                                    invoke EndDialog, hWnd,NULL
                                .ENDIF
                        .ENDIF
        .ELSE
                mov eax,FALSE
                ret
     .ENDIF
        mov eax,TRUE
     ret
DlgProc endp





calcolo proc aVariabile:dword
	
	push ebx
        push esi
	mov esi, aVariabile 
	push edi
	push ebp
	xor edi, edi
	invoke lstrlen, aVariabile
	test esi, esi
	je @@salto1
	test eax, eax
	je @@salto1
	mov ecx, 00000000
	jle @@salto1
@@salto2:	
	movsx ebx, byte ptr [eax+ecx+dati1] 
	movsx ebp, byte ptr [esi+ecx]
	lea edx, dword ptr [ecx+01]
	imul ebx, ebp
	movsx ecx, byte ptr [ecx+dati2]     
	imul ebx, ecx
	imul ebx, edx
	add edi, ebx
	mov ecx, edx
	cmp eax, edx
	jg @@salto2
@@salto1:	
	mov eax, edi
	pop ebp
	pop edi
	pop esi
	pop ebx
	
	ret
calcolo endp  

end start 

---------------------------------------------

Non credo che il keygen abbia bisogno di particolari spiegazioni bastera'
confrontare la parte di codice che esegue le call a "calcolo" con qella del
programma preso in esame alla locazione  00416D90 e la routine "calcolo"
con la parte di programma che parte dall'indirizzo 00417260.


Un ringraziamento ad Iczelion x i suoi tutes sul win32asm e a tutti i membri
di RingZero!! 

Pusillus.
SORGENTI